﻿using Microsoft.EntityFrameworkCore;
using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants;

namespace IdentityCenter
{
    public static class RegisterMiddlewareExtensions
    {
        public static async Task<WebApplication> SetupMiddleware(this WebApplication app)
        {
            if (!app.Environment.IsDevelopment())
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseCors(b => b.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:5112"));


            app.UseHttpsRedirection();
            app.UseStaticFiles();

            // Create new application registrations matching the values configured in Zirku.Client1 and Zirku.Api1.
            // Note: in a real world application, this step should be part of a setup script.
            await using (var scope = app.Services.CreateAsyncScope())
            {
                var context = scope.ServiceProvider.GetRequiredService<DbContext>();
                await context.Database.EnsureCreatedAsync();

                await CreateApplicationsAsync();
                await CreateScopesAsync();

                async Task CreateApplicationsAsync()
                {
                    var manager = scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();

                    if (await manager.FindByClientIdAsync("console_app") is null)
                    {
                        await manager.CreateAsync(new OpenIddictApplicationDescriptor
                        {
                            ClientId = "console_app",
                            RedirectUris =
                {
                    new Uri("http://localhost:8739/")
                },
                            Permissions =
                {
                    Permissions.Endpoints.Authorization,
                    Permissions.Endpoints.Token,
                    Permissions.GrantTypes.AuthorizationCode,
                    Permissions.ResponseTypes.Code,
                    Permissions.Scopes.Email,
                    Permissions.Scopes.Profile,
                    Permissions.Scopes.Roles,
                    Permissions.Prefixes.Scope + "api1",
                    Permissions.Prefixes.Scope + "api2"
                }
                        });
                    }

                    if (await manager.FindByClientIdAsync("spa") is null)
                    {
                        await manager.CreateAsync(new OpenIddictApplicationDescriptor
                        {
                            ClientId = "spa",
                            Type = ClientTypes.Public,
                            RedirectUris =
                {
                    new Uri("http://localhost:5112/index.html"),
                    new Uri("http://localhost:5112/signin-callback.html"),
                    new Uri("http://localhost:5112/signin-silent-callback.html"),
                },
                            Permissions =
                {
                    Permissions.Endpoints.Authorization,
                    Permissions.Endpoints.Logout,
                    Permissions.Endpoints.Token,
                    Permissions.GrantTypes.AuthorizationCode,
                    Permissions.GrantTypes.RefreshToken,
                    Permissions.ResponseTypes.Code,
                    Permissions.Scopes.Email,
                    Permissions.Scopes.Profile,
                    Permissions.Scopes.Roles,
                    Permissions.Prefixes.Scope + "api1",
                    Permissions.Prefixes.Scope + "api2"
                },
                            Requirements =
                {
                    Requirements.Features.ProofKeyForCodeExchange,
                },
                        });
                    }

                    if (await manager.FindByClientIdAsync("resource_server_1") is null)
                    {
                        await manager.CreateAsync(new OpenIddictApplicationDescriptor
                        {
                            ClientId = "resource_server_1",
                            ClientSecret = "846B62D0-DEF9-4215-A99D-86E6B8DAB342",
                            Permissions =
                {
                    Permissions.Endpoints.Introspection
                }
                        });
                    }

                    // Note: no client registration is created for resource_server_2
                    // as it uses local token validation instead of introspection.
                }

                async Task CreateScopesAsync()
                {
                    var manager = scope.ServiceProvider.GetRequiredService<IOpenIddictScopeManager>();

                    if (await manager.FindByNameAsync("api1") is null)
                    {
                        await manager.CreateAsync(new OpenIddictScopeDescriptor
                        {
                            Name = "api1",
                            Resources =
                {
                    "resource_server_1"
                }
                        });
                    }

                    if (await manager.FindByNameAsync("api2") is null)
                    {
                        await manager.CreateAsync(new OpenIddictScopeDescriptor
                        {
                            Name = "api2",
                            Resources =
                {
                    "resource_server_2"
                }
                        });
                    }
                }
            }

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseRouting();

            app.UseAuthorization();

            app.MapRazorPages();
            return app;
        }
    }
}
